import { useEffect, useCallback, useRef, useState } from 'react';
import { UnlistenFn } from '@tauri-apps/api/event';
import { tauri } from '@utils/tauri';
import { useAppActions } from '@stores/appStore';
import toast from 'react-hot-toast';

/**
 * Hook for Tauri command invocation with loading state
 */
export function useTauriCommand<T = any>(command: string) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [data, setData] = useState<T | null>(null);

  const invoke = useCallback(
    async (args?: any): Promise<T | null> => {
      setLoading(true);
      setError(null);

      try {
        const result = await tauri.invoke<T>(command, args);
        setData(result);
        return result;
      } catch (err) {
        const errorMessage =
          err instanceof Error ? err.message : 'Unknown error';
        setError(errorMessage);
        toast.error(`Command failed: ${errorMessage}`);
        return null;
      } finally {
        setLoading(false);
      }
    },
    [command]
  );

  return { invoke, loading, error, data };
}

/**
 * Hook for listening to Tauri events
 */
export function useTauriEvent<T = any>(
  event: string,
  callback: (payload: T) => void,
  deps: React.DependencyList = []
) {
  const callbackRef = useRef(callback);
  const unlistenRef = useRef<UnlistenFn | null>(null);

  // Update callback ref when callback changes
  useEffect(() => {
    callbackRef.current = callback;
  }, [callback]);

  useEffect(() => {
    let mounted = true;

    const setupListener = async () => {
      try {
        const unlisten = await tauri.listen<T>(event, payload => {
          if (mounted) {
            callbackRef.current(payload);
          }
        });

        if (mounted) {
          unlistenRef.current = unlisten;
        } else {
          unlisten();
        }
      } catch (error) {
        console.error(`Failed to listen to event "${event}":`, error);
      }
    };

    setupListener();

    return () => {
      mounted = false;
      if (unlistenRef.current) {
        unlistenRef.current();
        unlistenRef.current = null;
      }
    };
  }, [event, ...deps]);

  const emit = useCallback(
    async (payload?: any) => {
      try {
        await tauri.emit(event, payload);
      } catch (error) {
        console.error(`Failed to emit event "${event}":`, error);
        toast.error(`Failed to emit event: ${error}`);
      }
    },
    [event]
  );

  return { emit };
}

/**
 * Hook for window state management
 */
export function useWindowState() {
  const { setWindowState } = useAppActions();
  const [isMaximized, setIsMaximized] = useState(false);
  const [isMinimized, setIsMinimized] = useState(false);
  const [isVisible, setIsVisible] = useState(true);
  const [isFocused, setIsFocused] = useState(true);

  // Listen to window events
  useTauriEvent('tauri://window-maximized', () => {
    setIsMaximized(true);
    setWindowState({ isMaximized: true });
  });

  useTauriEvent('tauri://window-unmaximized', () => {
    setIsMaximized(false);
    setWindowState({ isMaximized: false });
  });

  useTauriEvent('tauri://window-minimized', () => {
    setIsMinimized(true);
    setWindowState({ isMinimized: true });
  });

  useTauriEvent('tauri://window-unminimized', () => {
    setIsMinimized(false);
    setWindowState({ isMinimized: false });
  });

  useTauriEvent('tauri://window-focus', () => {
    setIsFocused(true);
    setWindowState({ isFocused: true });
  });

  useTauriEvent('tauri://window-blur', () => {
    setIsFocused(false);
    setWindowState({ isFocused: false });
  });

  // Window control functions
  const windowControls = {
    minimize: useCallback(async () => {
      try {
        await tauri.window.minimize();
      } catch (error) {
        toast.error('Failed to minimize window');
      }
    }, []),

    maximize: useCallback(async () => {
      try {
        if (isMaximized) {
          await tauri.window.unmaximize();
        } else {
          await tauri.window.maximize();
        }
      } catch (error) {
        toast.error('Failed to toggle maximize');
      }
    }, [isMaximized]),

    close: useCallback(async () => {
      try {
        await tauri.window.close();
      } catch (error) {
        toast.error('Failed to close window');
      }
    }, []),

    show: useCallback(async () => {
      try {
        await tauri.window.show();
        setIsVisible(true);
        setWindowState({ isVisible: true });
      } catch (error) {
        toast.error('Failed to show window');
      }
    }, [setWindowState]),

    hide: useCallback(async () => {
      try {
        await tauri.window.hide();
        setIsVisible(false);
        setWindowState({ isVisible: false });
      } catch (error) {
        toast.error('Failed to hide window');
      }
    }, [setWindowState]),

    center: useCallback(async () => {
      try {
        await tauri.window.center();
      } catch (error) {
        toast.error('Failed to center window');
      }
    }, []),

    setAlwaysOnTop: useCallback(async (alwaysOnTop: boolean) => {
      try {
        await tauri.window.setAlwaysOnTop(alwaysOnTop);
      } catch (error) {
        toast.error('Failed to set always on top');
      }
    }, []),
  };

  return {
    isMaximized,
    isMinimized,
    isVisible,
    isFocused,
    ...windowControls,
  };
}

/**
 * Hook for file system operations
 */
export function useFileSystem() {
  const openFile = useCallback(async (options?: any) => {
    try {
      return await tauri.fs.openFile(options);
    } catch (error) {
      toast.error('Failed to open file');
      return null;
    }
  }, []);

  const openFiles = useCallback(async (options?: any) => {
    try {
      return await tauri.fs.openFiles(options);
    } catch (error) {
      toast.error('Failed to open files');
      return null;
    }
  }, []);

  const openDirectory = useCallback(async (options?: any) => {
    try {
      return await tauri.fs.openDirectory(options);
    } catch (error) {
      toast.error('Failed to open directory');
      return null;
    }
  }, []);

  const saveFile = useCallback(async (options?: any) => {
    try {
      return await tauri.fs.saveFile(options);
    } catch (error) {
      toast.error('Failed to save file');
      return null;
    }
  }, []);

  return {
    openFile,
    openFiles,
    openDirectory,
    saveFile,
  };
}

/**
 * Hook for notifications
 */
export function useNotifications() {
  const [permission, setPermission] = useState<
    'granted' | 'denied' | 'default'
  >('default');

  useEffect(() => {
    const checkPermission = async () => {
      const granted = await tauri.notifications.isPermissionGranted();
      setPermission(granted ? 'granted' : 'default');
    };

    checkPermission();
  }, []);

  const requestPermission = useCallback(async () => {
    try {
      const result = await tauri.notifications.requestPermission();
      setPermission(result);
      return result;
    } catch (error) {
      toast.error('Failed to request notification permission');
      return 'denied';
    }
  }, []);

  const sendNotification = useCallback(
    async (options: { title: string; body?: string; icon?: string }) => {
      try {
        if (permission !== 'granted') {
          const newPermission = await requestPermission();
          if (newPermission !== 'granted') {
            throw new Error('Notification permission denied');
          }
        }

        await tauri.notifications.send(options);
      } catch (error) {
        console.error('Failed to send notification:', error);
        toast.error('Failed to send notification');
      }
    },
    [permission, requestPermission]
  );

  return {
    permission,
    requestPermission,
    sendNotification,
  };
}

/**
 * Hook for global shortcuts
 */
export function useGlobalShortcuts() {
  const registeredShortcuts = useRef<Set<string>>(new Set());

  const registerShortcut = useCallback(
    async (shortcut: string, callback: () => void) => {
      try {
        await tauri.shortcuts.register(shortcut, callback);
        registeredShortcuts.current.add(shortcut);
      } catch (error) {
        console.error(`Failed to register shortcut "${shortcut}":`, error);
        toast.error(`Failed to register shortcut: ${shortcut}`);
      }
    },
    []
  );

  const unregisterShortcut = useCallback(async (shortcut: string) => {
    try {
      await tauri.shortcuts.unregister(shortcut);
      registeredShortcuts.current.delete(shortcut);
    } catch (error) {
      console.error(`Failed to unregister shortcut "${shortcut}":`, error);
    }
  }, []);

  const unregisterAllShortcuts = useCallback(async () => {
    try {
      await tauri.shortcuts.unregisterAll();
      registeredShortcuts.current.clear();
    } catch (error) {
      console.error('Failed to unregister all shortcuts:', error);
    }
  }, []);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      unregisterAllShortcuts();
    };
  }, [unregisterAllShortcuts]);

  return {
    registerShortcut,
    unregisterShortcut,
    unregisterAllShortcuts,
    registeredShortcuts: Array.from(registeredShortcuts.current),
  };
}

/**
 * Hook for app configuration
 */
export function useAppConfig() {
  const { setConfig } = useAppActions();
  const { invoke: getConfig, loading: loadingGet } =
    useTauriCommand('get_app_config');
  const { invoke: saveConfig, loading: loadingSave } =
    useTauriCommand('set_app_config');

  const loadConfig = useCallback(async () => {
    const config = await getConfig();
    if (config) {
      setConfig(config);
    }
  }, [getConfig, setConfig]);

  const updateConfig = useCallback(
    async (newConfig: any) => {
      const success = await saveConfig({ frontendConfig: newConfig });
      if (success) {
        setConfig(newConfig);
        toast.success('Configuration saved');
      }
    },
    [saveConfig, setConfig]
  );

  return {
    loadConfig,
    updateConfig,
    loading: loadingGet || loadingSave,
  };
}
